from math import log, exp
from operator import itemgetter

def meanSquareDistance (list1, list2):
    """
    Calculates the mean square distance between two lists of equal length.
    """
    if len(list1)!=len(list2):
        raise "List length not equal."
    
    sum=0
    for x, y in zip(list1, list2):
        sum += (x - y)**2
    sum /= len(list1)
    return sum
    
    

def listAbsDistance (list1, list2):
    """
    Returns a list which holds the absolute value of the difference between list1 and list2.
    Lengths must be equal.
    """
    if len(list1)!=len(list2):
        raise "List length not equal."
    
    sum=[]
    for x, y in zip(list1, list2):
        sum += [abs(x - y)]
    
    return sum

def calcHarmonics (size):
    """
    Calculates the value of the harmonic series of length size.
    """
    sum=0
    for i in range (1, size):
        sum += 1/float(i)
    return sum  

def sortByPageRank (list):
    """
    Returns a list, sorted by PageRank.
    """
    listrank=[]    
    sortlist=sorted(enumerate(list), key=itemgetter(1))
    
    for i,(id,pagerank) in enumerate(sortlist):
        listrank += [id]
    return listrank  

def weightedPageRankMetricOld (list1,list2):
    """
    Calculates the absolute value difference between two weighted lists.
    Uses sortAndWeight.
    """
    
    if len(list1)!=len(list2):
        raise "List length not equal."
  
    lsort1 = sortByPageRank (list1)
    lsort2 = sortByPageRank (list2)
    value= []
    
    for (index1,id) in enumerate(lsort1):
        index2 = lsort2.index(id)
        a = 1/float(index1+1)
        b = 1/float(index2+1)
        value += [abs(a - b)]
    
    return value


def weightedPageRankMetric (x,y):
    """
        Weighting by X - With LOG.
        
        NORMALIZE THIS SHIT
        
        
    """

    if len(x)!=len(y):
        raise "List length not equal."

    alpha = 2/float(max(x)+ max(y))

    val = [] 
    for i in range (0,len(x)-1):
        
        val += [abs (x[i] - y[i]) * (exp ((x[i]+y[i])*alpha)) ] 
    
    return val


def normList(L, rangeMin=0, rangeMax=1):
    '''Normalize values of a list between values of rangeMin and rangeMax.
    List L may have negative values.
    '''

    vMin = float(min(L))
    vMax = float(max(L))
  
#    xTra = abs(vMin/(vMax-vMin))

    return [ ( x- vMin) /(vMax-vMin)+1 for x in L]

        

def logList (list):
    """
    Calculates the logarithmic values of a list.
    """
    
    loglist=[]
    for x in list:
        if (x>0):
            loglist += [log(x)]
        elif (x==0):
            loglist += [0]
        else:
            print "FUCKING ERROR"
    
    return loglist


def bin_variance(x,y,bins=20):
    def variance(lst):
        avg=sum(lst)*1.0/len(lst)
        squared=reduce(lambda a,b: a+b**2,lst,0)*1.0/len(lst)
        return squared - avg*avg
    
    d_x=list(enumerate(x))
    d_x.sort(key=lambda v:v[1])
    step=len(d_x)/bins
    x_out=[]
    y_out=[]
    for i in xrange(0,len(d_x),step):
        input_bin=d_x[i:i+step]
        output_bin=map(lambda v:y[v[0]],input_bin)
        x_out.append((input_bin[0][1]+input_bin[-1][1])/2.0)
        y_out.append(variance(output_bin)/variance(input_bin))
    return {'x':x_out,'y':y_out}
    